iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
Mobile Development

Flutter基礎入門系列 第 28

【Day 28】時刻表的使用 - 續篇

  • 分享至 

  • xImage
  •  

今日筆者將繼續在時刻表上做功能的設定,並且修改與優化過去的相關程式碼。下列為前幾篇與時刻表相關的文章:
【Day 26】建立客製化的時刻表吧!
【Day 27】儲存時刻表的新資料

到了鐵人賽末期就開始有點怠惰,懶的再回去修改之前的內容了_(¦3」∠)_


過去程式碼的修正

await open()

本次受到更動的檔案主要為data/models/blocks.dart中的BlocksDb,修改內容簡單來說,就是在各個函式中呼叫open()時,先等待它跑完,再繼續執行下面的程式(就是加個await keyword而已),避免資料庫未開啟就對資料庫做讀寫。

老實說,我是因為少了await而遇到了程式的bug,在那邊debug了半天,終於找到問題的關鍵 。゚(゚´ω`゚)゚。

詳細程式碼如下:
blocks.dart

abstract class BlocksDb extends ChangeNotifier {
  String dbFilename, tableName, executeSQL;
  bool dbIsOpen;
  Database? db;

  BlocksDb(
      {required this.dbFilename,
      required this.tableName,
      required this.executeSQL})
      : dbIsOpen = false;

  DateTime setTime(
          {int month = 0, int day = 0, int hour = 0, int minute = 0}) =>
      DateTime(2000, month, day, hour, minute);

  Future<String> get _localPath async {...}
  Future open() async {...}

  Future<Block> insert(Block block) async {
    if (!dbIsOpen) await open();

    block.id = await db?.insert(tableName, block.toMap());
    if (kDebugMode) {
      print('$tableName: ${block.name} inserted');
    }
    notifyListeners();
    return block;
  }

  Future<void> delete(int id) async {
    if (!dbIsOpen) await open();

    await db?.delete(tableName, where: 'id = ?', whereArgs: [id]);
    notifyListeners();
  }

  Future<void> update(Block block) async {
    if (!dbIsOpen) await open();

    await db?.update(tableName, block.toMap(),
        where: 'id = ?', whereArgs: [block.id]);
    notifyListeners();
  }

  Future close() async {
    dbIsOpen = false;
    return await db?.close();
  }

  Future getCount() async =>
      await db?.execute('SELECT COUNT(*) from $tableName');
}

time_blocks.dart

class TimeBlocksDb extends BlocksDb {
  ...
  
  Future<List<TimeBlock>?> getAll() async {
    if (!dbIsOpen) await open();
    List<Map<String, Object?>>? table =
        await db?.rawQuery('SELECT * FROM $tableName');
    notifyListeners();
    return table?.map((data) => TimeBlock().toBlock(data)).toList();
}

todo_blocks.dart

class TodoBlocksDb extends BlocksDb {
  ...
  
    Future<List<TodoBlock>?> getAll() async {
    if (!dbIsOpen) await open();

    List<Map<String, Object?>>? table =
        await db?.rawQuery('SELECT * FROM $tableName');
    notifyListeners();
    return table?.map((data) => TodoBlock().toBlock(data)).toList();
  }
}

儲存event的錯誤修正

之前的程式中,將資料存於資料庫的動作是在_onCreateEvent中執行,而筆者發現這會使得建立物件的結束時間永遠都在開始時間的15分鐘後,很明顯,這其中有個bug。後續發現儲存應該要改放在_onEventCreated,也就是事件已經建立好了之後,再去執行。

應該也會有人跟筆者有相同的疑惑,這兩者間有什麼差別?在kalender的說明文件中是如此寫到:
https://ithelp.ithome.com.tw/upload/images/20241012/20169446trISBgg4e2.png
我們可以將他們理解為:

  1. onCreateEvent:事件建立的當下,也就是點擊了事件起始時間時。此時使用者還未完成結束時間的設定。
  2. onEventCreated:事件已經完成建立,並暫時不會做更改。也就是使用者拖拉完成,已設定好結束時間。

那麼問題原因就很清楚啦!現在只要把insert()移到後者,問題就解決了!修改後的程式碼如下:

  CalendarEvent<TimeBlock> _onCreateEvent(DateTimeRange dateTimeRange) {
    return CalendarEvent(
      dateTimeRange: dateTimeRange,
      eventData: TimeBlock.name('new event'),
    );
  }

  Future<void> _onEventCreated(CalendarEvent<TimeBlock> event) async {
    // Add the event to the events controller.
    eventController.addEvent(event);

    // Deselect the event.
    eventController.deselectEvent();
    event.eventData!.setTimes(event.start, event.end);
    db?.insert(event.eventData!);
  }

本篇中加入的新功能!

讀取資料庫中的資料

此部份為用於讀取過去使用者在Timetable頁面建立並存在資料庫中的資料,並將他們加回到Timetable頁面中。在此使用了then()來等待資料庫開啟並對其中的資料做讀取。

class _TimetablePageState extends State<TimetablePage> {
  ...
  
  TimeBlocks? db;
  @override
  void initState() {
    super.initState();

    // load events from database
    db = TimeBlocksDb();
    db?.getAll().then((List<TimeBlock>? timeblocksdb) {
      if (timeblocksdb != null) {
        for (TimeBlock block in timeblocksdb) {
          eventController.addEvent(CalendarEvent(
            dateTimeRange:
                DateTimeRange(start: block.startTime, end: block.endTime),
            eventData: block,
          ));
        }
        if (kDebugMode) {
          print('Fetched ${timeblocksdb.length} events from the database');
        }
      } else if (kDebugMode) {
        print('No events found in database');
      }
    });
  }
  
  ...
}

謝謝閱讀到這裡的讀者,有任何想說的都歡迎留言與email,明天會繼續努力的!

最後是筆者的一點小小內心戲**——**
今天debug花的時間比預計的還要多,因此沒辦法達成昨日預期的進度 (☍﹏⁰。),明天在世試看將它補上吧。


上一篇
【Day 27】儲存時刻表的新資料
下一篇
【Day 29】為Block增添色彩吧!
系列文
Flutter基礎入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言